#pragma once
#include "Common.hpp"

// 定长内存池
template <class T>
class ObjectPool
{
public:
    // 内存池的使用默认构造和析构即可，不允许拷贝
    // 其生命周期随进程，申请的所有空间会在进程结束时释放，不需要手动释放
    ObjectPool() = default;
    ObjectPool(const ObjectPool &) = delete;
    ObjectPool &operator=(const ObjectPool &) = delete;

    T *New()
    {
        T *obj = nullptr;
        _mtx.lock();
        // 先从自由链表获取可用空间
        if (_freeList != nullptr)
        {
            obj = (T *)_freeList;
            _freeList = *(void **)_freeList;
        }
        else
        {
            // 从主内存池中申请空间
            // 空间不足应该向系统申请新内存
            if (_remainSize < s_sgBlock)
            {
                _memory = (char*)SystemAlloc(s_ctnBlock >> PAGE_SHIFT);
                _remainSize = s_ctnBlock;
            }
            obj = (T *)_memory;
            _memory += s_sgBlock;
            _remainSize -= s_sgBlock;
        }
        _mtx.unlock();
        new(obj)T; //定位new，初始化对象
        return obj;
    }

    void Delete(T *&obj)
    {
        if (obj == nullptr)
        {
            throw "Delete error: nullptr";
        }

        obj->~T(); //调用析构，清理对象
        _mtx.lock();
        *(void **)obj = _freeList;
        _freeList = obj;
        _mtx.unlock();
        obj = nullptr;
    }

private:
    static const size_t s_sgBlock = sizeof(T) > sizeof(void *) ? sizeof(T) : sizeof(void *); // 单个内存块的大小
    static const size_t s_ctnBlock = 128 * 1024;                                             // 新申请的连续内存块的大小128KB
    char *_memory = nullptr;   // 主内存池，保存申请到的待分配空间
    void *_freeList = nullptr; // 自由链表，保存释放空间
    size_t _remainSize = 0;    // 主内存池中的剩余空间大小
    std::mutex _mtx;
};
